﻿using System;
using System.Diagnostics;               //Processes
using System.IO;                        //File I/O
using System.Threading;                 //Threading
using System.Windows;
using System.Windows.Automation;
using WinForms = System.Windows.Forms;
using System.Windows.Input;
using GUI.Custom_Classes;
using Tedds_Tool;
using System.Collections.ObjectModel;
using System.Windows.Data;
using System.Windows.Controls;
using System.ComponentModel;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using Compiled_Tests.Utils;
using System.Xml.Serialization;
using RulesBase;
using System.Windows.Media;
using Microsoft.Win32;
using System.Xml;
using System.Media;
using Ins = Tedds_Tool.Instructions;
using System.Windows.Automation.Provider;
using System.Collections;
using System.Runtime.InteropServices;
using Tedds_Tool.Compilers.LEET;
using Tedds_Tool.Automatables;
using Compiled_Tests;
using UIAutomationCPP;
using LEET.Utilities;
using GUI.Tabs;

namespace GUI
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
       
        
        #region Attributes


        /// <summary>
        /// The absolute coordinates (relative to the upper-left screen)
        /// of the mouse pointer.
        /// </summary>
        /// 

        private ILEETFactory factory;
        private IAlerts alerts;
        private Settings _settings;
        public  IScriptFinder ScriptFinder{ get; private set; }
        private int ruleSelect;

        /// <summary>
        /// Variable for Add Rules window for list box manipulation. This is to enable selecting
        /// certain items on load if editing is selected.
        /// </summary>
        private AddRules ar;

        /// <summary>
        /// 
        /// </summary>
        private LEETCompilerFactory cFac;

        /// <summary>
        /// Default root directory of MS test framework.
        /// </summary>
        private string MSpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), @"Microsoft.NET\assembly\GAC_MSIL\Microsoft.VisualStudio.QualityTools.UnitTestFramework");

        /// <summary>
        /// LEET managed provider interfaces for custom patterns.
        /// </summary>
        //private ManagedServerProvider msp;
        //private ManagedClientProvider mcp;
        //private ManagedRotateWrapper mrw;

        #endregion

        public Settings settings
        {
            get
            {
                return _settings;
            }
            set
            {
                _settings = value;

                if (settings.ProjectRoot != null)
                {
                    projectPathText.Text = settings.ProjectRoot.FullName;
                    AddTooltip(projectPathText);
                    App.Log("ProjectPath: " + settings.ProjectRoot.FullName);
                }
                if (settings.TestDLL != null)
                {
                    testDLLPath.Text = settings.TestDLL.FullName;
                    AddTooltip(testDLLPath);
                    App.Log("DllPath: " + settings.TestDLL.FullName);
                }

                settings.OnPropertyChanged += new PropertyChangedEvent(ReloadInfo);
                mainTab.Factory = factory;
                mainTab.init(null, default(DependencyPropertyChangedEventArgs));
                mainTab.OnSettingsChange(settings);
            }
        }

        /// <summary>
        /// The main window of LEET's GUI.
        /// </summary>
        public Window1()
        {
            InitializeComponent();
            alerts = new MessageBoxAlerts(this);
            RuleBasesRulesEditorView.KeyDown += new KeyEventHandler(RB_DeleteRule_Button);
            Capture_Replay_Tab.IsEnabled = false;
            Capture_Replay_Tab.IsEnabledChanged += mainTab.init;
            if (Application.Current != null)
                Application.Current.ShutdownMode = ShutdownMode.OnMainWindowClose;

            Closing += mainTab.CheckedIfSaveNeeded;
            
            //msp = new ManagedServerProvider();
            //mrw = new ManagedRotateWrapper();
            //mcp = new ManagedClientProvider(mrw);
        }

        #region Test Creator View

        /// <summary>
        /// Initializes and refreshes viewing panes on startup and when changes are made.
        /// Viewing panes affected are for the test creator tab and the rules base tab.
        /// </summary>
        public void ReloadScriptInfo(Object sender, RoutedEventArgs e)
        {
            mainTab.OnSettingsChange(settings);
            ScriptFinder = new ScriptFinder(settings);
            ActivateTabs();
        }

        /// <summary>
        /// Reloads info for viewing approprietly when the workspace path has changed
        /// to show the available files.
        /// </summary>
        private void ReloadInfo(object sender, String e)
        {
            ReloadScriptInfo(sender, null);
        }

        private void loadRuleBasesRulesEditorView()
        {
            loadListBox(RuleBasesRulesEditorView, ScriptFinder.ListRules());
        }

        private void loadSetOfCons()
        {
            if(ar != null) loadCheckListBox(ar.SetofCons, ScriptFinder.ListConsequences());
        }

        private void loadSetOfActions()
        {
            if (ar != null) loadCheckListBox(ar.SetofActions, ScriptFinder.ListActions());
        }

        private void loadSetOfPreconds()
        {
            if (ar != null) loadCheckListBox(ar.SetofPreconds, ScriptFinder.ListPreconditions());
        }

        private void loadCheckListBox(ListBox lb, IEnumerable<String> values)
        {
            if (lb.IsLoaded)
            {
                CheckBox check;
                lb.Items.Clear();
                foreach (String i in values)
                {
                    check = new CheckBox();
                    check.Width = 240;
                    check.Checked += new RoutedEventHandler(CheckboxesChecked);
                    check.Unchecked += new RoutedEventHandler(CheckboxesChecked);
                    check.Content = i;
                    lb.Items.Add(check);
                }
            }
        }

        private void loadListBox(ListBox lb, IEnumerable<String> values)
        {
            if (lb.IsLoaded)
            {
                lb.Items.Clear();
                foreach (String i in values)
                {
                    ListBoxItem item = new ListBoxItem();
                    item.Width = 240;
                    item.Content = i;
                    item.MouseDown += new MouseButtonEventHandler(
                        delegate(object sender, MouseButtonEventArgs args)
                        {
                            lb.SelectedItem = sender;
                        }
                    );
                    lb.Items.Add(item);
                }
            }
        }

        /// <summary>
        /// Initializes label and location to correspond to those matching the given listbox.
        /// </summary>
        /// <param name="listbox">The ListBox to load with items from location.</param>
        /// <param name="label">The Label labeling the given ListBox.</param>
        /// <param name="location">The Path corresponding to the filenames to be loaded into the given ListBox.</param>
        private void WhichListBox(ref ListBox listbox, out Label label) 
        {
            if (listbox != null) 
            {
                if (listbox == RuleBasesRulesEditorView)
                {
                    listbox = RuleBasesRulesEditorView;
                    label = RuleBasesRulesView;
                    return;
                }
                else if (listbox == ar.SetofPreconds)
                {
                    listbox = ar.SetofPreconds;
                    label = ar.LabelPrecond;
                    return;
                }
                else if (listbox == ar.SetofActions)
                {
                    listbox = ar.SetofActions;
                    label = ar.LabelAct;
                    return;
                }
                else if (listbox == ar.SetofCons)
                {
                    listbox = ar.SetofCons;
                    label = ar.LabelCons;
                    return;
                }
            }
            label = null;
        }

        /// <summary>
        /// Called whenever the item in Test_Scripts is changed.  If there are no items in 
        /// Test_Scripts, or none is selected, then the null pointer is handled.
        /// </summary>
        private void Label_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Label label;
            ListBox listbox = (sender as ListBox);

            WhichListBox(ref listbox, out label);

            label.Content = (label.Name.Contains("Rules_") ? "Rule Base: " : "Test Script: ")
                + (listbox.SelectedItem == null ? "" : (listbox.SelectedItem as ListBoxItem).Content);
        }

        #endregion

        #region Rule Base Buttons
        
        /// <summary>
        /// Allows rules to be added from a modal dialog and saved to the appropriate rules directory.
        /// </summary>
        private void RB_AddRule_Button(object sender, RoutedEventArgs e)
        {
            ar = new AddRules(this, null, null);
            ar.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
            ar.Owner = this;
            ar.ShowDialog();
            RuleForceSave(sender, e);
        }

        /// <summary>
        /// Allows rules to be edited from a modal dialog.
        /// </summary>
        private void RB_EditRule_Button(object sender, RoutedEventArgs e)
        {
            //check if there is a Rule highlighted.
            if (SelectedRule() == null)
            {
                alerts.Alert("Button Requirement: Select a Rule to view and edit.");
            }
            else
            {
                using (TextReader reader = ScriptFinder.FindRule(SelectedRule().Content.ToString()))
                {
                    ar = new AddRules(this, SelectedRule().Content.ToString(), reader);
                    ar.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
                    ar.Owner = this;
                    ar.ShowDialog();
                    RuleForceSave(sender, e);
                }
            }
        }

        /// <summary>
        /// Deletes a rule from the workspace and removes it from the viewing pane.
        /// </summary>
        private void RB_DeleteRule_Button(object sender, RoutedEventArgs args)
        {
            if (args is KeyEventArgs)
            {
                KeyEventArgs kargs = args as KeyEventArgs;
                if (kargs.Key.CompareTo(Key.Delete) != 0)
                    return;
            }
            //check if there is a Rule highlighted.
            if (SelectedRule() == null)
            {
                MessageBox.Show("Button Requirement: Select a Rule to delete.", "Requirement", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
            }
            else
            {
                string name = SelectedRule().Content.ToString();
                ScriptFinder.DeleteRule(name);
                ReloadScriptInfo(sender, args);
            }
        }

        private ListBoxItem SelectedRule()
        {
            return (ListBoxItem)RuleBasesRulesEditorView.SelectedItem;
        }

        /// <summary>
        /// Deletes the selected rules base from the workspace and removes it from the viewing pane.
        /// </summary>
        //private void RBDeleteClick(object sender, RoutedEventArgs e)
        //{
        //    //check if there is a Rule highlighted.
        //    if (RuleBasesRBEditorView.SelectedItem == null)
        //    {
        //        MessageBox.Show("Button Requirement: Select a Rules Base to delete.", "Requirement", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
        //    }
        //    else
        //    {
        //        string name = ((ListBoxItem)RuleBasesRBEditorView.SelectedItem).Content.ToString();
        //        ScriptFinder.DeleteRule(name);
        //        ReloadScriptInfo(sender, e);
        //    }
        //}

        #endregion

        #region Rule Base Helper Functions

        
        /// <summary>
        /// Event handler to highlight & check the current item.
        /// </summary>
        /// <param name="sender">The current item to process.</param>
        /// <param name="e">Event argument for the current item.</param>
        private void RulesSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (ruleSelect != -1)
            {
                if (((ListBox)sender).SelectedItem != null && ruleSelect == ((ListBox)sender).SelectedIndex)
                    ((ListBox)sender).UnselectAll();

                ruleSelect = ((ListBox)sender).SelectedIndex;
            }
            else if (((ListBox)sender).SelectedItem != null)
            {
                ruleSelect = ((ListBox)sender).SelectedIndex;
            }
        }

        /// <summary>
        /// Event handler for checkboxes to highlight & check the current item.
        /// </summary>
        /// <param name="sender">The current item to process.</param>
        /// <param name="e">Event argument for the current item.</param>
        public void CheckboxesChecked(object sender, RoutedEventArgs e)
        {
            if (((CheckBox)sender).IsChecked == true)
                ((ListBox)((CheckBox)sender).Parent).SelectedItem = sender;
            else
                ((ListBox)((CheckBox)sender).Parent).SelectedItem = sender;
        }

        /// <summary>
        /// Checks if all items in rules base viewing pane is a list box item.
        /// </summary>
        //private void CheckForTextBox(object sender, MouseButtonEventArgs e)
        //{
        //    toListBoxItem();
        //}

        /// <summary>
        /// Forces saving of the current new/edited rule on the main thread.
        /// </summary>
        private void RuleForceSave(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty(ar.name))
            {
                BackgroundWorker bgw = new BackgroundWorker();
                bgw.DoWork += new DoWorkEventHandler(delegate
                {
                    using (TextWriter sw = ScriptFinder.CreateRule(Helpers.NormalizeClassName(ar.name))) { sw.Write(ar.save); }
                });

                bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(delegate
                {
                    ReloadScriptInfo(sender, e);
                    MessageBox.Show("Rule Base " + ar.name + " saved successfully.", "Save Complete", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
                    ar = null;
                });

                bgw.RunWorkerAsync();
            }
        }

        #endregion
       
        #region Project Workspace Functionality

        private void SelectTestDLL_Click(object sender, RoutedEventArgs e)
        {
            WinForms.OpenFileDialog browser = new WinForms.OpenFileDialog();
            if (settings != null)
            {
                browser.InitialDirectory = MSpath;
                browser.FileName = "";
            }
            browser.Filter = "dll files (*.dll)|*.dll";

            WinForms.DialogResult dr;
            if ((dr = browser.ShowDialog()) == WinForms.DialogResult.OK)
            {
                if (settings == null)
                    settings = new Settings(null);

                testDLLPath.Text = browser.FileName;
                settings.TestDLL = new FileInfo(testDLLPath.Text);
                AddTooltip(testDLLPath);
            }
        }

        private string getMsTestPath()
        {
            if (Directory.Exists(MSpath))
            {
                DirectoryInfo dir = new DirectoryInfo(MSpath);
                DirectoryInfo[] dirs = dir.GetDirectories();
                return Path.Combine(dirs[dirs.Length - 1].FullName, "Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll");
            }
            return string.Empty;
        }

        private void SelectProjectRoot_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog browser = new System.Windows.Forms.FolderBrowserDialog();
            if (settings != null && settings.ProjectRoot != null)
                browser.SelectedPath = settings.ProjectRoot.FullName;
            System.Windows.Forms.DialogResult result = browser.ShowDialog();
            if (result.CompareTo(System.Windows.Forms.DialogResult.OK) == 0)
            {
                settings.ProjectRoot = new DirectoryInfo(browser.SelectedPath);
                projectPathText.Text = browser.SelectedPath;
                ReloadScriptInfo(this, null);
                AddTooltip(projectPathText);
            }
        }

        private void AddTooltip(TextBox tb)
        {
            TextBlock tbl = new TextBlock();
            tbl.Text = tb.Text;
            ToolTipService.SetToolTip(tb, tbl);
            ToolTipService.SetShowOnDisabled(tb, true);
        }

        private void ActivateTabs()
        {
            if (settings.ProjectRoot != null && settings.TestDLL != null && !string.IsNullOrEmpty(settings.TestDLL.FullName))
            {
                File.WriteAllText(App.ProgramConfigPath, settings.ProjectRoot.FullName + "\r\n" + settings.TestDLL.FullName);

                this.Capture_Replay_Tab.IsEnabled = true;
                this.Rule_Base_Editor_Tab.IsEnabled = true;
                loadSetOfPreconds();
                loadSetOfActions();
                loadSetOfCons();
                loadRuleBasesRulesEditorView();
            }
        }

        #endregion



        private void TT_GUI_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                factory = new LEETFactory(new Box());
                mainTab.Factory = factory;

                this.Closing += mainTab.TT_GUI_Closing;
                ActivateTabs();

                if (settings == null || settings.ProjectRoot == null || settings.TestDLL == null)
                {
                    this.Capture_Replay_Tab.IsEnabled = false;
                    this.Rule_Base_Editor_Tab.IsEnabled = false;
                    this.Settings_Tab.Focus();
                }

                RegistryKey key = Registry.LocalMachine.OpenSubKey("Software\\LEET - Enhances Exploratory Testing");
                if (key != null)
                {
                    //if ((string)key.GetValue("TestFramework") == "1")
                    //{
                        testDLLPath.Text = getMsTestPath();
                        settings.testDLL = new FileInfo(testDLLPath.Text);
                    //}
                }
            }
            catch (Exception ex)
            {
                App.Log(ex.Message + "\r\n" + ex.StackTrace.ToString());
                throw new Exception("Logged Inner.", ex);
            }
        }

        

        private void CheckAdvancedOptions(object sender, RoutedEventArgs e)
        {
            //TODO: Move this into the settings object (Go' Damit)
            mainTab.Script_Viewer.TestCleanup    = testCleanupBox == null  || testCleanupBox.IsChecked == true;
            mainTab.Script_Viewer.TestScreenShot = testScreenShots == null || testScreenShots.IsChecked == true;
        }
    }
}
